import sys
import time
import tkinter as tk
import traceback
import random
import string
import smtplib
from email.mime.text import MIMEText
from tkinter import ttk, messagebox
from PIL import Image, ImageTk  # 用于处理背景图片
from werkzeug.security import generate_password_hash, check_password_hash  # 新增导入

# 尝试导入数据库和用户模块，失败时提供模拟类
try:
    from LibrarySystem.database_option import Database
    from LibrarySystem.main_ui import LibraryUI
    from LibrarySystem.user_init import User
except ImportError:
    # 模拟类用于测试
    class Database:
        def get_user(self, username):
            # 模拟返回用户数据
            if username == "test":
                return {
                    "id": 1,
                    "username": "test",
                    "password_hash": generate_password_hash("test123"),
                    "role": "regular",
                    "email": "test@example.com",
                    "phone": "13800138000"
                }
            return None

        def add_user_by_admin(self, username, password_hash, role, email, phone):
            return True, "用户添加成功"

        def log_action(self, user_id, action_type, details):
            pass


    class User:
        def __init__(self, user_data):
            self.user_data = user_data

        def verify_password(self, password):
            return check_password_hash(self.user_data["password_hash"], password)


    class LibraryUI:
        def __init__(self, username, main_window=None, db=None):
            self.username = username
            self.main_window = main_window
            self.db = db

        def protocol(self, name, func):
            pass

        def mainloop(self):
            print(f"LibraryUI started for user: {self.username}")

        def on_close(self):
            if self.main_window:
                self.main_window.deiconify()

# 颜色配置
BG_COLOR = "#f0f8ff"  # 背景色
BTN_COLOR = "#4CAF50"  # 默认按钮颜色
TEXT_COLOR = "#333333"  # 文字颜色
ACCENT_COLOR = "#45a049"  # 强调按钮颜色
REGISTER_COLOR = "#2196F3"  # 注册按钮颜色
LOGIN_COLOR = "#FF9800"  # 登录按钮颜色
EXIT_COLOR = "#F44336"  # 退出按钮颜色
FONT = ("微软雅黑", 12)

# 邮件配置 (需要替换为实际的邮件服务器配置)
EMAIL_CONFIG = {
    'host': 'smtp.qq.com',  # QQ邮箱SMTP服务器地址
    'port': 465,  # QQ邮箱SSL端口
    'username': '你的qq邮箱',  # 你的QQ邮箱
    'password': '你的邮箱密码或授权码',  # 邮箱密码或授权码
    'from': '你的qq邮箱.com'  # 发件人邮箱(通常与username相同)
}


class AuthSystem:
    def __init__(self):
        self.db = Database()
        self.current_user = None
        self.bg_image = None  # 存储背景图片引用
        self.verification_code = None  # 存储验证码
        self.code_expiry = None  # 验证码过期时间
        self.entries = {}  # 存储注册窗口中的输入框

    def create_window(self, title, size, bg_image_path=None):
        """创建带有背景图片的窗口"""
        window = tk.Toplevel()
        window.title(title)
        window.geometry(size)
        window.resizable(False, False)

        # 设置窗口图标
        try:
            logo_image = self._load_image("logo.png")
            if logo_image:
                logo_photo = ImageTk.PhotoImage(logo_image)
                window.iconphoto(False, logo_photo)
        except Exception as e:
            print(f"加载窗口图标失败: {str(e)}")

        # 设置背景图片
        if bg_image_path:
            try:
                image = self._load_image(bg_image_path)
                if image:
                    image = image.resize((800, 600), Image.LANCZOS)
                    self.bg_image = ImageTk.PhotoImage(image)
                    bg_label = tk.Label(window, image=self.bg_image)
                    bg_label.place(x=0, y=0, relwidth=1, relheight=1)
                else:
                    window.configure(bg=BG_COLOR)
            except Exception as e:
                print(f"加载背景图片失败: {str(e)}")
                window.configure(bg=BG_COLOR)
        else:
            window.configure(bg=BG_COLOR)

        return window

    def _load_image(self, image_name, default_dir="images"):
        """尝试从多个位置加载图片"""
        try:
            # 尝试相对路径
            image = Image.open(f"{default_dir}/{image_name}")
            return image
        except FileNotFoundError:
            try:
                # 尝试绝对路径
                image = Image.open(
                    f"绝对路径/{image_name}")
                return image
            except FileNotFoundError:
                print(f"图片 {image_name} 未找到")
                return None

    def close_window(self, current_window, main_window):
        """安全关闭当前窗口并显示主窗口"""
        try:
            if current_window and current_window.winfo_exists():
                current_window.destroy()
            if main_window and main_window.winfo_exists():
                main_window.deiconify()
        except tk.TclError as e:
            print(f"窗口操作异常: {str(e)}")

    def register(self, root, main_window):
        """创建注册窗口"""
        try:
            main_window.withdraw()

            register_window = self.create_window("用户注册", "800x600", "logo.png")

            # 主容器 - 使用place布局居中
            container = tk.Frame(register_window, bg="white", bd=2, relief=tk.RIDGE)
            container.place(relx=0.5, rely=0.5, anchor="center", width=600, height=550)

            # 标题
            ttk.Label(container, text="用户注册", font=("微软雅黑", 16, "bold"),
                      background="white").pack(pady=20)

            # 表单框架 - 使用grid布局确保对齐
            form_frame = tk.Frame(container, bg="white")
            form_frame.pack(pady=10, padx=20, fill=tk.BOTH)

            # 统一设置标签和输入框的宽度
            label_width = 10
            entry_width = 30

            # 表单字段
            fields = [
                ("用户名:", "username", None),
                ("密码:", "password", "*"),
                ("确认密码:", "confirm_password", "*"),
                ("邮箱:", "email", None),
                ("电话:", "phone", None)
            ]

            self.entries = {}
            for i, (label_text, field_name, show_char) in enumerate(fields):
                # 标签
                label = ttk.Label(form_frame, text=label_text, width=label_width,
                                  background="white", font=FONT, anchor="e")
                label.grid(row=i, column=0, padx=5, pady=5, sticky="e")

                # 输入框
                entry = ttk.Entry(form_frame, width=entry_width, font=FONT, show=show_char)
                entry.grid(row=i, column=1, padx=5, pady=5, sticky="w")
                self.entries[field_name] = entry

            # 验证码部分
            ttk.Label(form_frame, text="验证码:", width=label_width,
                      background="white", font=FONT, anchor="e").grid(row=len(fields), column=0, padx=5, pady=5,
                                                                      sticky="e")

            code_frame = tk.Frame(form_frame, bg="white")
            code_frame.grid(row=len(fields), column=1, padx=5, pady=5, sticky="w")

            self.entries["verification_code"] = ttk.Entry(code_frame, width=15, font=FONT)
            self.entries["verification_code"].pack(side=tk.LEFT)

            ttk.Button(code_frame, text="获取验证码", style="Accent.TButton",
                       command=self._send_verification_code).pack(side=tk.LEFT, padx=5)

            # 按钮区域
            btn_frame = tk.Frame(container, bg="white")
            btn_frame.pack(pady=20)

            ttk.Button(btn_frame, text="返回", style="Cancel.TButton",
                       command=lambda: self.close_window(register_window, main_window)).pack(side=tk.LEFT, padx=10)
            ttk.Button(btn_frame, text="注册", style="Accent.TButton",
                       command=lambda: self.do_register(
                           self.entries["username"].get(),
                           self.entries["password"].get(),
                           self.entries["confirm_password"].get(),
                           self.entries["email"].get(),
                           self.entries["phone"].get(),
                           self.entries["verification_code"].get(),
                           register_window,
                           main_window
                       )).pack(side=tk.LEFT, padx=10)

            # 配置grid列权重，使输入框对齐
            form_frame.columnconfigure(0, weight=1)
            form_frame.columnconfigure(1, weight=3)

        except Exception as e:
            messagebox.showerror("界面错误", f"创建注册窗口失败: {str(e)}")
            main_window.deiconify()

    def _send_verification_code(self):
        """发送验证码到用户邮箱"""
        try:
            email = self.entries["email"].get()
            if not email or "@" not in email:
                raise ValueError("请输入有效的邮箱地址")

            # 生成6位随机验证码
            self.verification_code = ''.join(random.choices(string.digits, k=6))
            self.code_expiry = time.time() + 300  # 5分钟后过期

            # 邮件内容
            msg = MIMEText(f"您的图书馆系统注册验证码是: {self.verification_code}\n验证码5分钟内有效。")
            msg['Subject'] = '图书馆系统注册验证码'
            msg['From'] = EMAIL_CONFIG['from']
            msg['To'] = email

            try:
                # 根据端口选择SSL或普通连接
                if EMAIL_CONFIG['port'] == 465:
                    # SSL加密连接
                    server = smtplib.SMTP_SSL(EMAIL_CONFIG['host'], EMAIL_CONFIG['port'])
                else:
                    # 普通连接(通常需要后续starttls)
                    server = smtplib.SMTP(EMAIL_CONFIG['host'], EMAIL_CONFIG['port'])
                    server.starttls()  # 启用TLS加密

                # 登录服务器
                server.login(EMAIL_CONFIG['username'], EMAIL_CONFIG['password'])

                # 发送邮件
                server.sendmail(EMAIL_CONFIG['from'], [email], msg.as_string())
                server.quit()

                messagebox.showinfo("发送成功", "验证码已发送到您的邮箱，请查收！")
            except smtplib.SMTPAuthenticationError:
                raise ValueError("邮件服务器认证失败，请检查用户名和密码/授权码")
            except smtplib.SMTPException as e:
                raise ValueError(f"发送邮件失败: {str(e)}")

        except ValueError as e:
            messagebox.showerror("错误", str(e))
        except Exception as e:
            messagebox.showerror("错误", f"发送验证码时发生异常: {str(e)}")

    def do_register(self, username, password, confirm_password, email, phone, verification_code, window, main_window):
        """处理用户注册请求"""
        try:
            # 验证输入
            if not username or not password:
                raise ValueError("用户名和密码不能为空")

            if len(username) < 3 or len(username) > 20:
                raise ValueError("用户名长度必须在3-20个字符之间")

            if password != confirm_password:
                raise ValueError("两次输入的密码不一致")

            if not email or "@" not in email:
                raise ValueError("邮箱格式不正确")

            if phone and (len(phone) != 11 or not phone.isdigit()):
                raise ValueError("电话号码必须是11位数字")

            # 验证验证码
            if not verification_code:
                raise ValueError("请输入验证码")

            if not self.verification_code or time.time() > self.code_expiry:
                raise ValueError("验证码已过期，请重新获取")

            if verification_code != self.verification_code:
                raise ValueError("验证码不正确")

            # 检查用户名是否已存在
            if self.db.get_user(username):
                raise ValueError("用户名已存在")

            # 创建用户
            password_hash = generate_password_hash(password)

            # 添加到数据库
            success, message = self.db.add_user_by_admin(username, password_hash, "regular", email, phone)
            if not success:
                raise ValueError(message)

            # 记录日志
            self.db.log_action(None, 'USER_REGISTER', f'Username: {username}, Email: {email}')

            # 注册成功后自动登录
            user_data = self.db.get_user(username)
            if user_data:
                self.current_user = User(user_data)
                messagebox.showinfo("注册成功", f"欢迎 {username}，已自动登录！")

                # 关闭所有窗口
                self.close_window(window, None)
                if main_window and main_window.winfo_exists():
                    main_window.withdraw()

                # 创建图书馆主界面
                app = LibraryUI(username, main_window=main_window, db=self.db)
                app.protocol("WM_DELETE_WINDOW", app.on_close)
                app.mainloop()
            else:
                raise ValueError("注册成功但登录失败，请手动登录")

        except ValueError as e:
            messagebox.showerror("注册错误", str(e))
        except Exception as e:
            if main_window and main_window.winfo_exists():
                main_window.deiconify()
            messagebox.showerror("注册错误", f"注册过程中发生异常: {str(e)}")
            traceback.print_exc()

    def login(self, root, main_window):
        """创建登录窗口"""
        try:
            main_window.withdraw()

            login_window = self.create_window("用户登录", "800x600", "logo.png")

            # 主容器
            container = tk.Frame(login_window, bg="white", bd=2, relief=tk.RIDGE)
            container.place(relx=0.5, rely=0.5, anchor="center", width=500, height=300)

            # 标题
            ttk.Label(container, text="用户登录", font=("微软雅黑", 16, "bold"),
                      background="white").pack(pady=20)

            # 表单框架 - 使用grid布局确保对齐
            form_frame = tk.Frame(container, bg="white")
            form_frame.pack(pady=10, padx=20, fill=tk.BOTH)

            # 统一设置标签和输入框的宽度
            label_width = 8
            entry_width = 25

            # 用户名
            ttk.Label(form_frame, text="用户名:", width=label_width,
                      background="white", font=FONT, anchor="e").grid(row=0, column=0, padx=5, pady=5, sticky="e")
            self.username_entry = ttk.Entry(form_frame, width=entry_width, font=FONT)
            self.username_entry.grid(row=0, column=1, padx=5, pady=5, sticky="w")

            # 密码
            ttk.Label(form_frame, text="密码:", width=label_width,
                      background="white", font=FONT, anchor="e").grid(row=1, column=0, padx=5, pady=5, sticky="e")
            self.password_entry = ttk.Entry(form_frame, width=entry_width, show="*", font=FONT)
            self.password_entry.grid(row=1, column=1, padx=5, pady=5, sticky="w")

            # 配置grid列权重，使输入框对齐
            form_frame.columnconfigure(0, weight=1)
            form_frame.columnconfigure(1, weight=3)

            # 按钮区域
            btn_frame = tk.Frame(container, bg="white")
            btn_frame.pack(pady=20)

            ttk.Button(btn_frame, text="返回", style="Cancel.TButton",
                       command=lambda: self.close_window(login_window, main_window)).pack(side=tk.LEFT, padx=10)
            ttk.Button(btn_frame, text="登录", style="Accent.TButton",
                       command=lambda: self._do_login(
                           self.username_entry.get(),
                           self.password_entry.get(),
                           login_window,
                           main_window
                       )).pack(side=tk.LEFT, padx=10)

        except Exception as e:
            messagebox.showerror("界面错误", f"创建登录窗口失败: {str(e)}")
            main_window.deiconify()

    def _do_login(self, username, password, window, main_window):
        """处理用户登录请求"""
        try:
            if not username or not password:
                raise ValueError("用户名和密码不能为空")

            # 使用Database类获取用户
            user_data = self.db.get_user(username)
            if not user_data:
                raise ValueError("用户不存在")

            # 创建用户对象
            user = User(user_data)

            # 验证密码
            if not user.verify_password(password):
                raise ValueError("密码错误")

            self.current_user = user

            # 关闭所有窗口
            self.close_window(window, None)
            if main_window and main_window.winfo_exists():
                main_window.withdraw()

            # 创建图书馆主界面
            app = LibraryUI(username, main_window=main_window, db=self.db)
            app.protocol("WM_DELETE_WINDOW", app.on_close)
            app.mainloop()

        except ValueError as e:
            messagebox.showerror("验证错误", str(e))
        except Exception as e:
            if main_window and main_window.winfo_exists():
                main_window.deiconify()
            messagebox.showerror("登录错误", f"登录过程中发生异常: {str(e)}")
            traceback.print_exc()


def main():
    """主函数，启动图书馆系统"""
    try:
        root = tk.Tk()
        root._is_destroyed = False
        root.title("图书馆管理系统")
        root.geometry("800x600")

        # 设置窗口图标
        try:
            logo_image = Image.open("logo.png")
            logo_photo = ImageTk.PhotoImage(logo_image)
            root.iconphoto(False, logo_photo)
        except Exception as e:
            print(f"加载窗口图标失败: {str(e)}")

        # 设置背景图片
        try:
            bg_image = Image.open("bg.png")
            bg_image = bg_image.resize((800, 600), Image.LANCZOS)
            bg_photo = ImageTk.PhotoImage(bg_image)

            bg_label = tk.Label(root, image=bg_photo)
            bg_label.place(x=0, y=0, relwidth=1, relheight=1)
            bg_label.image = bg_photo  # 保持引用
        except Exception as e:
            print(f"加载背景图片失败: {str(e)}")
            root.configure(bg=BG_COLOR)

        # 设置窗口关闭事件处理
        def on_closing():
            if not root._is_destroyed:
                if messagebox.askokcancel("退出", "您确定要退出系统吗？"):
                    root._is_destroyed = True
                    root.destroy()
                    sys.exit(0)

        root.protocol("WM_DELETE_WINDOW", on_closing)

        # 样式配置 - 为不同按钮设置不同样式
        style = ttk.Style()

        # 默认按钮样式
        style.configure('TButton',
                        font=FONT,
                        background=BTN_COLOR,
                        foreground="black",
                        borderwidth=1,
                        focusthickness=3,
                        focuscolor='none')
        style.map('TButton',
                  background=[('active', '#45a049'), ('disabled', '#cccccc')],
                  foreground=[('active', 'black'), ('disabled', '#888888')])

        # 强调按钮样式 (用于主要操作)
        style.configure('Accent.TButton',
                        font=FONT,
                        background=ACCENT_COLOR,
                        foreground="black",
                        borderwidth=1)
        style.map('Accent.TButton',
                  background=[('active', '#2E7D32'), ('disabled', '#cccccc')])

        # 注册按钮样式
        style.configure('Register.TButton',
                        font=FONT,
                        background=REGISTER_COLOR,
                        foreground="black",
                        borderwidth=1)
        style.map('Register.TButton',
                  background=[('active', '#0b7dda'), ('disabled', '#cccccc')])

        # 登录按钮样式
        style.configure('Login.TButton',
                        font=FONT,
                        background=LOGIN_COLOR,
                        foreground="black",
                        borderwidth=1)
        style.map('Login.TButton',
                  background=[('active', '#e68a00'), ('disabled', '#cccccc')])

        # 退出按钮样式
        style.configure('Exit.TButton',
                        font=FONT,
                        background=EXIT_COLOR,
                        foreground="black",
                        borderwidth=1)
        style.map('Exit.TButton',
                  background=[('active', '#d32f2f'), ('disabled', '#cccccc')])

        # 取消按钮样式
        style.configure('Cancel.TButton',
                        font=FONT,
                        background="#f0f0f0",
                        foreground="black",
                        borderwidth=1)
        style.map('Cancel.TButton',
                  background=[('active', '#e0e0e0'), ('disabled', '#cccccc')])

        # 主界面布局 - 使用Frame作为内容容器
        main_container = tk.Frame(root, bg="white")
        main_container.place(relx=0.5, rely=0.5, anchor="center", width=600, height=400)

        # 标题
        ttk.Label(main_container, text="欢迎使用图书馆管理系统",
                  font=("微软雅黑", 24, "bold"), background="white").pack(pady=(30, 40))

        # 按钮区域
        btn_frame = tk.Frame(main_container, bg="white")
        btn_frame.pack(pady=20)

        # 实例化权限系统
        auth = AuthSystem()

        ttk.Button(btn_frame, text="用户注册", style="Register.TButton",
                   command=lambda: auth.register(root, root)).pack(pady=10, ipadx=30, ipady=8)
        ttk.Button(btn_frame, text="用户登录", style="Login.TButton",
                   command=lambda: auth.login(root, root)).pack(pady=10, ipadx=30, ipady=8)
        ttk.Button(btn_frame, text="退出系统", style="Exit.TButton",
                   command=on_closing).pack(pady=10, ipadx=30, ipady=8)

        try:
            root.mainloop()
        except KeyboardInterrupt:
            on_closing()

    except Exception as e:
        messagebox.showerror("致命错误", f"系统启动失败: {str(e)}")
        traceback.print_exc()


if __name__ == "__main__":
    main()